package hr.utils;

import hr.entity.Employee;
import hr.exception.CustomException;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class TokenUtils {
    private final RedisTemplate<String, String> redisTemplate;

    /**
     * 通过构造函数进行注入。
     * RedisTemplate 是 Spring 提供的用于操作 Redis 数据库的模板类。
     */
    @Autowired
    public TokenUtils(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 令牌的过期时间（7天）
     * 1000ms *60s *60min *24h *7d
     */
//    private static final long EXPIRE_TIME = 1000 * 60 * 60 * 24 * 7;
    /**
     * 1 天
     */
//    private static final long EXPIRE_TIME = 1000 * 60 * 60 * 24;
    private static final long EXPIRE_TIME = TimeUnit.DAYS.toMillis(1);


    /**
     * 用于签名和验证JWT的密钥
     */
    private final static Key KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256);

    /**
     * 生成token
     * 由于只有当账号密码正确之后才会生成token所以这边只需要id或者是邮箱进行识别
     *
     * @param id 用户id
     * @return 生成的token
     */
    public String createToken(String id) {
        log.info("token key {}", KEY.toString());

        Map<String, Object> headerMap = new HashMap<>();
        headerMap.put("typ", "JWT");
        headerMap.put("alg", "HS256");

        Date expirationDate = new Date(System.currentTimeMillis() + EXPIRE_TIME);

        String token = Jwts.builder()
                .setHeader(headerMap)
                .setSubject(id)
                .setExpiration(expirationDate)
                .setIssuedAt(new Date())
                .signWith(KEY)
                .compact();
        // 将 token 存放的redis中
        redisTemplate.opsForValue().set(id, token);
        // 设置过期时间
        redisTemplate.expire(id, EXPIRE_TIME, TimeUnit.MILLISECONDS);
        return token;
    }

    public String createToken(Employee employee) {
        log.info("token key {}", KEY.toString());

        Map<String, Object> headerMap = new HashMap<>();
        headerMap.put("typ", "JWT");
        headerMap.put("alg", "HS256");

        Date expirationDate = new Date(System.currentTimeMillis() + EXPIRE_TIME);

        String token = Jwts.builder()
                .setHeader(headerMap)
                .setSubject(String.valueOf(employee.getEmployeeId()))
                .claim("name", employee.getName())
                .setExpiration(expirationDate)
                .setIssuedAt(new Date())
                .signWith(KEY)
                .compact();
        // 将 token 存放的redis中
        redisTemplate.opsForValue().set(String.valueOf(employee.getEmployeeId()), token);
        // 设置过期时间为30分钟
        redisTemplate.expire(String.valueOf(employee.getEmployeeId()), 30, TimeUnit.MINUTES);
        return token;
    }


    /**
     * 根据token校验该token是否合法，或获取凭据值然后进行查库操作
     *
     * @param token
     * @return
     */
    public Boolean checkToken(String token) throws Exception {
        log.info("token key {}", KEY.toString());

        try {
            JwtParser jwtParser = Jwts.parserBuilder()
                    .setSigningKey(KEY)
                    .build();

            Jws<Claims> jws = jwtParser.parseClaimsJws(token);
            Claims claims = jws.getBody();

            String id = claims.getSubject();
            String userToken = redisTemplate.opsForValue().get(id);

            if (userToken == null || userToken.isEmpty()) {
                throw new Exception("请先登录！");
            } else if (!userToken.equals(token)) {
                throw new Exception("权限校验失败");
            }

            return true;
        } catch (ExpiredJwtException e) {
            // Token过期
            log.info("Token过期");
            throw new Exception("当前账户登录已过期，请重新登录");
//            return false;
        }
    }

    /**
     * 根据token字符串获取构建该字符串的凭据
     *
     * @param token
     * @return
     */
    public static String getKey(String token) {
        log.info("token key {}", KEY.toString());

        JwtParser jwtParser = Jwts.parserBuilder()
                .setSigningKey(KEY)
                .build();
        Jws<Claims> jws = jwtParser.parseClaimsJws(token);
        Claims claims = jws.getBody();
        return claims.getSubject();
    }

    /**
     * 获取token 体 中的name
     *
     * @param token
     * @return
     */
    public static String extractNameFromToken(String token) throws CustomException {
        if (token==null|| token.isEmpty()){
            throw new CustomException("请先登录！");
        }

        JwtParser jwtParser = Jwts.parserBuilder()
                .setSigningKey(KEY)
                .build();

        Jws<Claims> jws = jwtParser.parseClaimsJws(token);
        Claims claims = jws.getBody();
        return claims.get("name", String.class);
    }
}